package res;

import com.codahale.metrics.annotation.Timed;
import mybatis.TeacherDao;
import mybatis.UserDao;
import mybatis.conf.MybatisConf;
import org.apache.ibatis.session.SqlSession;
import orm.*;
import util.JWTToken;

import javax.validation.constraints.NotNull;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by langdon on 2017/7/10.
 */

@Path("/api/v1/tokens")
@Produces(MediaType.APPLICATION_JSON)
public class TokenRes {

    private static Map userMap = new HashMap<Integer , String >();

    public TokenRes() {
        System.out.println("TokenRes");
    }


    /**
     * 用户登录函数
     * @param user 用户名
     * @param password 密码
     * @return 登录成功则返回加密后的token
     */
    @GET
    @Timed
    public Result login(
            @NotNull@QueryParam("user")String user,
            @NotNull@QueryParam("password")String password
    ){
        SqlSession sqlSession = MybatisConf.getSession();
        try
        {
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User theUser = userDao.getByName(user);

            if(theUser==null){
                return new Result(Status.NOT_FOUND ,"login failed.Can not find this user!");
            }

            int userId = theUser.getId();
            String auth;
            if(theUser.getPassword().equals(password)){
                if(userMap.containsKey(userId)){
                    auth=(String) userMap.get(userId);
                }else {
                    auth = JWTToken.encode(theUser.getId());
                    userMap.put(theUser.getId(),auth);
                    System.out.println("oldAuth = "+auth);
                }
                return new TokenResult(Status.SUCCESS,"login successfully",auth);
            }
            else
            {
                return new Result(Status.ERROR,"login failed，wrong password");
            }
        }
        finally {
            sqlSession.close();
        }



    }

    /**
     * 认证权限函数
     * @param auth 用户认证的token
     * @return  根据result的状态码判断是否成功
     */
    @POST
    @Timed
    public Result verifyAuthority(
            @NotNull@QueryParam("auth")String auth,
            @NotNull@QueryParam("privilege")int privilege
    ){
        SqlSession sqlSession = MybatisConf.getSession();

        try
        {
            TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
            Token oldToken = JWTToken.decode(auth);
            int userId = Integer.parseInt((String )oldToken.getPayload().get("id"));

            String oldAuth = (String) userMap.get(userId);
            System.out.println("oldAuth = "+oldAuth);
            System.out.println("auth = "+auth);
            if(oldAuth.equals(auth)) {
                //有效的auth
                long validTime = Long.parseLong((String)oldToken.getPayload().get("exp"));
                if (System.currentTimeMillis() < validTime){
                    //未过期的auth
                    //最低权限,直接放行
                    if(privilege==Privilege.STUDENT){
                        String newAuth =  JWTToken.encode(userId);
                        userMap.put(userId,newAuth);
                        return  new TokenResult(Status.SUCCESS,"Success",newAuth);
                    }

                    //判断权限是否足够
                    if(privilege==Privilege.TEACHER){
                        Teacher teacher = teacherDao.getTeacherByUId(userId);
                        if(teacher!=null){
                            //在teacher 表中找到了，则权限足够
                            String newAuth =  JWTToken.encode(userId);
                            userMap.put(userId,newAuth);
                            return  new TokenResult(Status.SUCCESS,"Success",newAuth);
                        }
                        else return new Result(Status.NOT_ENOUGH_PRIVILEGE,"Refused");

                    }else return new Result(Status.NOT_FOUND,"Refused");

                }
                //过期的auth
                else return new Result(Status.NO_AUTH," Authentication failed ! Please login again");
            }
            //无效的auth
            else return new Result(Status.NO_AUTH," Authentication failed ! Please login again");
        }
        finally {
            sqlSession.close();
        }


    }

    /**
     * 更新用户的token，实际上更新了访问的有效时间
     * @param auth 鉴权的token
     * @return 返回更新后的token
     */
    @PUT
    @Timed
    public Result updateToken (
            @NotNull@QueryParam("auth")String auth
    ){

            Token oldToken = JWTToken.decode(auth);
            int userId = Integer.parseInt((String)oldToken.getPayload().get("id"));

            String oldAuth = (String) userMap.get(userId);
            if(oldAuth.equals(auth)) {
                //有效的auth
                long validTime = Long.parseLong((String)oldToken.getPayload().get("exp") );
                if (System.currentTimeMillis() < validTime){
                    //未过期的auth
                    String newAuth =  JWTToken.encode(userId);
                    userMap.put(userId,newAuth);
                    return  new TokenResult(Status.SUCCESS,"Update auth successfully",newAuth);
                }
                //过期的auth
                else return new Result(Status.NO_AUTH,"Authentication failed ! Please login again");

            }
            //无效的auth
            else return new Result(Status.NO_AUTH , "Authentication failed ! Please login again");

    }

    /**
     * 登出
     * @param auth 认证
     * @return 结果
     */
    @DELETE
    @Path("/{auth}")
    @Timed
    public Result logout(@PathParam("auth")String auth){
        Token oldToken = JWTToken.decode(auth);
        int userId = Integer.parseInt((String)oldToken.getPayload().get("id"));

        userMap.remove(userId);
        return new Result(Status.SUCCESS,"logout success");
    }

    /**
     * 管理员强制用户下线
     * @return
     */
    @DELETE
    @Path("/admin/userId/{userId}")
    @Timed
    public Result logout2(@PathParam("userId")int userId){
        SqlSession sqlSession = MybatisConf.getSession();
        try
        {
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getByUId(userId);
            if(user!=null){
                if(userMap.containsKey(userId)){
                    userMap.remove(userId);
                    return new Result(Status.SUCCESS,user.getUserName()+" logout successfully");
                }
            }
            return new Result(Status.NOT_FOUND,"Please login and then  try logout!");
        }
        finally {
            sqlSession.close();
        }

    }

    @DELETE
    @Path("/admin/user/{user}")
    @Timed
    public Result logout3(@PathParam("user")String name){
        SqlSession sqlSession = MybatisConf.getSession();
        try
        {
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            User user = userDao.getByName(name);
            if(user!=null){
                int userId = user.getId();
                if(userMap.containsKey(userId)){
                    userMap.remove(userId);
                    return new Result(Status.SUCCESS,user.getUserName()+" logout successfully");
                }
            }
            return new Result(Status.NOT_FOUND,"Please login and then try logout!");
        }
        finally {
            sqlSession.close();
        }

    }
}